package com.definity.toolkit.web.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import br.com.caelum.vraptor.Result;

import com.definity.toolkit.I18nException;
import com.definity.toolkit.domain.Domain;
import com.definity.toolkit.message.Message;
import com.definity.toolkit.message.MessageType;
import com.definity.toolkit.service.DataService;
import com.definity.toolkit.web.util.ItemMock;

public abstract class DWTDataController<D extends Domain<?>> extends DWTController {

	public DWTDataController(Result result, HttpServletRequest request) {
		super(result, request);
	}

	public void index() {
		forwardTo(getClass()).list();
	}
	
	@SuppressWarnings("unchecked")
	public void create() {
		forwardTo(getClass()).edit(createDomain());
	}
	
	public D edit(D domain) {
		if (domain == null || domain.getId() == null)
			return domain;
		
		return getService().view(domain);
	}
	
	public void save(D domain) {
		List<Message> messages = new ArrayList<Message>();
		validate(domain, messages);
		
		if (!messages.isEmpty()) {
			for (Message message : messages) {
				addMessage(message);
			}
			errorSaveRedirect(domain);
			return;
		}
		
		D entity = domain;

		try {
			entity = getService().save(domain);
		} catch (I18nException e) {
			logger.error(e.getMessage(), e);
			addMessage(new Message(e.getMessage(), MessageType.ERROR));
			errorSaveRedirect(domain);
			return;
		}
		successfulSaveRedirect(entity);
	}

	public void delete(D domain) {
		try {
			domain = getService().view(domain);
			getService().delete(domain);
			successfulDeleteRedirect(domain);
		} catch (I18nException e) {
			logger.error(e.getMessage(), e);
			addMessage(new Message(e.getMessage(), MessageType.ERROR));
			errorDeleteRedirect(domain);
		}
	}
	
	public List<D> list() {
		return getService().listAll();
	}

	public void jsonList(ToItemMock<D> toItemMock) {
		List<ItemMock> list = new ArrayList<ItemMock>();
		
		List<D> listAll = getService().listAll();
		for (D d : listAll) {
			list.add(toItemMock.make(d));
		}
		
		json(list).serialize();
	}
	
	protected void validate(D domain, List<Message> messages) {

	}
	
	protected void successfulSaveRedirect(D domain) {
		successfulRedirect(domain);
	}

	protected void successfulDeleteRedirect(D domain) {
		successfulRedirect(domain);
	}
	
	protected void successfulRedirect(D domain) {
		redirectTo(getClass()).index();
	}

	@SuppressWarnings("unchecked")
	protected void errorRedirect(D domain) {
		forwardTo(getClass()).edit(domain);
	}

	protected void errorSaveRedirect(D domain) {
		errorRedirect(domain);
	}

	protected void errorDeleteRedirect(D domain) {
		errorRedirect(domain);
	}

	protected abstract D createDomain();

	protected abstract DataService<D> getService();

	protected interface ToItemMock<D extends Domain<?>> {
		ItemMock make(D domain);
	}
	
}
